package diagnose

import (
	"cloud_worm/worm/config"
	"net/http"
	_ "net/http/pprof"
	"fmt"
	"time"
	"github.com/golang/glog"
	"runtime/debug"
	"os"
	"strings"
	"strconv"
	"io/ioutil"
	"runtime"
	"path/filepath"
	"cloud_worm/util/proto/ujson"
	"cloud_worm/worm/client"
)

func pprofSrv()  {
	if config.CfgInst.IsClient() {
		if config.CfgInst.StartConfig.(*config.ClientConfig).LocalConfig.PprofEnable {
			go func() {
				addr := fmt.Sprintf("%s:%s", config.CfgInst.LocalAddr, config.CfgInst.StartConfig.(*config.ClientConfig).LocalConfig.PprofPort)
				httpServer := &http.Server{
					Addr: addr,
					Handler: nil,
					IdleTimeout: 90 * time.Second,
				}
				if err := httpServer.ListenAndServe(); err != nil {
					glog.Fatal("pprof server start error: " + err.Error())
				}
			}()
		}
	}
}

func statSrv(version int) {
	// TODO：暂时设置线程上限为：100
	debug.SetMaxThreads(100)

	gcPercent := 100
	for {
		// 内存设置
		var rssOrSys uint64
		memInfo := MemInfo{}
		if err := getMemInfo(&memInfo); err != nil {
			stat := runtime.MemStats{}
			runtime.ReadMemStats(&stat)
			rssOrSys = stat.Sys / 1024
		} else {
			rssOrSys = uint64(memInfo.VmRSS)
		}
		if rssOrSys >= 61440 && gcPercent == 100 {			// 超过60M，则尝试增加gc次数
			gcPercent = 50
			debug.SetGCPercent(gcPercent)
		} else if rssOrSys < 61440 && gcPercent == 50 {
			gcPercent = 100
			debug.SetGCPercent(gcPercent)
		}

		// 采集目录中占用磁盘空间大小
		var size int64
		varDir := ""					// TODO：待实现
		fInfos, err := ioutil.ReadDir(varDir)
		if err != nil {
			glog.Errorf("read var dir error: %s", err.Error())
		}
		for _, item := range fInfos {
			size += item.Size()
		}

		// 协程数
		numGo := runtime.NumGoroutine()

		statInfo := ujson.StatInfo{
			NumGo: numGo,
			MemSys: rssOrSys,
			VarDirSize: size,
		}
		// 封装协议包
		if payload, err := statInfo.MarshalJSON(); err == nil {
			pushMsg := ujson.PushMsg{
				Type: ujson.PushStatMsg,
				Payload: payload,
			}
			if protoMsg, err := pushMsg.MarshalJSON(); err == nil {
				msg := ujson.ProtoMsg{
					Type: ujson.ProtoMsgPush,
					Content: protoMsg,
				}
				if buf, err := msg.MarshalJSON(); err == nil {
					client.AgentInst.PushMsgC <- buf
				} else {
					glog.Errorf("process run stat error: %s", err.Error())
				}
			} else {
				glog.Errorf("process run stat error: %s", err.Error())
			}
		} else {
			glog.Errorf("process run stat error: %s", err.Error())
		}

		time.Sleep(50 * time.Second)
		clearLogFile(varDir)
	}

}

func Diagnose()  {
	pprofSrv()
	go statSrv(config.CfgInst.Version)
}

// 内存信息
type MemInfo struct {
	VmRSS		int
}

// TODO: 暂时是linux平台，后续是再支持其他平台
func getMemInfo(m *MemInfo) error {
	pid := os.Getpid()
	data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
	if err != nil {
		return err
	}
	lines := strings.Split(string(data), "\n")
	for _, l := range lines {
		l := strings.TrimSpace(l)
		if len(l) <= 0 {
			continue
		}

		if strings.HasPrefix(l, "VmRSS:") {
			tmps := strings.Split(l, ":")
			if len(tmps) == 2 {
				t := strings.TrimSpace(tmps[1])
				ts := strings.Split(t, " ")
				if len(ts) == 2 {
					if rss, err := strconv.Atoi(strings.TrimSpace(ts[0])); err != nil {
						glog.Errorf("read rss'%s' error: %s", ts[0], err.Error())
					} else {
						m.VmRSS = rss
					}
				}
			}
			break
		}
	}

	return nil
}

func clearLogFile(varDir string) {
	fInfos, err := ioutil.ReadDir(varDir)
	if err != nil {
		glog.Errorf("read var dir for clearLogFile error: %s", err.Error())
		return
	}

	var monitorFileNum int
	for _, item := range fInfos {
		if strings.Contains(item.Name(), "monitor") {
			monitorFileNum++
		}
	}

	if monitorFileNum > 3 {
		for _, item := range fInfos {
			if strings.Contains(item.Name(), "monitor") == true && strings.Contains(item.Name(), "monitor.log") == false {
				glog.Errorf("remove file: %s", filepath.Join(varDir, item.Name()))
				os.Remove(filepath.Join(varDir, item.Name()))
			}
		}
	}

	return
}

